package com.tanhua.server.service;

import com.tanhua.commons.template.OssTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.db.UserStatus;
import com.tanhua.domain.mongo.Comment;
import com.tanhua.domain.mongo.Publish;
import com.tanhua.domain.mongo.Visitor;
import com.tanhua.domain.vo.PageResult;
import com.tanhua.domain.vo.PublishVO;
import com.tanhua.domain.vo.VisitorVO;
import com.tanhua.dubbo.api.*;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.util.RelativeDateFormat;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author liuyp
 * @date 2021/01/30
 */
@Slf4j
@Service
public class MovementsService {
    @Reference
    private PublishApi publishApi;
    @Reference
    private UserInfoApi userInfoApi;
    @Reference
    private CommentApi commentApi;
    @Reference
    private VisitorApi visitorApi;
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private MovementsMQService mqService;

    @Reference
    private UserStatusApi userStatusApi;

    /**
     * 查询  给当前用户推荐的动态列表
     *
     * @param page     页码
     * @param pagesize 查询几条
     */
    public ResponseEntity findRecommendPublishList(int page, int pagesize) {
        //1. 获取当前用户
        User user = UserHolder.getUser();

        //2. 优先从Redis里查询推荐的动态；如果Redis里没有，再调用API从MongoDB里查询
        PageResult<Publish> pageResult = findRecommendFromRedis(page, pagesize);
        if (pageResult == null) {
            pageResult = publishApi.findRecommendPublishList(user.getId(), page, pagesize);
        }

        //3. 转换成PublishVO对象
        List<Publish> publishList = pageResult.getItems();
        List<PublishVO> voList = new ArrayList<>();
        for (Publish publish : publishList) {
            PublishVO vo = new PublishVO();

            //查询动态的发布人信息，封装到vo对象
            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            vo.setTags(userInfo.getTags().split(","));

            //把Publish封装到vo对象
            BeanUtils.copyProperties(publish, vo);
            vo.setId(publish.getId().toHexString());
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setDistance("50米");
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));

            //如果当前用户已经点赞了此动态，这个值应该是1；否则是0
            Boolean hasLike = redisTemplate.hasKey("publish_like_" + user.getId() + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLike ? 1 : 0);

            vo.setHasLoved(0);

            voList.add(vo);
        }

        //4. 构造返回值
        PageResult<PublishVO> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult, voPageResult);
        voPageResult.setItems(voList);
        log.debug("查询给用户{}推荐的动态列表：{}", user.getId(), voPageResult);
        return ResponseEntity.ok(voPageResult);
    }

    private PageResult<Publish> findRecommendFromRedis(int page, int pagesize) {
        //先从Redis里获取数据  17,100092,100092,18,22,1,100092,100099,20,4
        String pidStr = redisTemplate.opsForValue().get("QUANZI_PUBLISH_RECOMMEND_" + UserHolder.getUserId());
        if (pidStr == null) {
            return null;
        }

        //查询推荐的动态总数量
        String[] pidArray = pidStr.split(",");
        int count = pidArray.length;

        //计算分了多少页
        int pages = (int) Math.ceil(count * 1.0 / pagesize);

        //查询某一页的动态列表
        if (page <= pages) {
            int start = (page - 1) * pagesize;
            int end = start + pagesize;

            if (end > count) {
                end = count;
            }

            List<Long> pidList = new ArrayList<>();
            for (int i = start; i < end; i++) {
                Long pid = Long.parseLong(pidArray[i]);
                pidList.add(pid);
            }

            List<Publish> publishList = publishApi.findPublishByPids(pidList);

            return new PageResult<>(count, pagesize, pages, page, publishList);
        }
        return new PageResult<>();
    }

    /**
     * 发布动态
     *
     * @param publish      动态信息对象
     * @param imageContent 提交的文件，是数组
     */
    public ResponseEntity savePublish(Publish publish, MultipartFile[] imageContent) throws IOException {


        Long userId = UserHolder.getUserId();

        UserInfo userInfo = userInfoApi.findById(userId);
        //校验用户是否冻结

        if (userInfo.getUserStatus().equals("2")) {
            UserStatus userStatus = userStatusApi.findByUserId(userId.intValue());
            Integer freezingRange = userStatus.getFreezingRange();
            if (freezingRange == 3) {
                return ResponseEntity.status(503).body("账户发布动态功能已封禁,");
            }
        }



        //1. 把图片文件存储到阿里云OSS
        List<String> mediaList = new ArrayList<>();
        if (imageContent != null && imageContent.length > 0) {
            for (MultipartFile file : imageContent) {
                String path = ossTemplate.upload(file.getOriginalFilename(), file.getInputStream());
                mediaList.add(path);
            }
        }

        //2. 补全数据
        publish.setUserId(UserHolder.getUserId());
        publish.setMedias(mediaList);
        publish.setSeeType(1);
        publish.setState(0);

        //3. 调用API，保存动态数据
        String publishId = publishApi.savePublish(publish);

        //4. 通过RocketMQ发送消息
        rocketMQTemplate.convertAndSend("tanhua-publish", publishId);
        log.info("发送消息进行动态审核，动态id：{}", publishId);

        //   给大数据推荐系统发送消息
        mqService.savePublishMessage(publishId);

        return ResponseEntity.ok(null);
    }

    /**
     * 查询当前用户的好友动态（查询当前用户的时间线数据）
     *
     * @param page
     * @param pagesize
     * @return
     */
    public ResponseEntity findFriendPublishList(int page, int pagesize) {
        //1. 获取当前用户
        Long userId = UserHolder.getUserId();

        //2. 查询当前用户的好友动态（时间线）
        PageResult<Publish> pageResult = publishApi.findTimelinePublishList(userId, page, pagesize);

        //3. 转换成PublishVO对象
        List<Publish> publishList = pageResult.getItems();
        List<PublishVO> voList = new ArrayList<>();
        for (Publish publish : publishList) {
            PublishVO vo = new PublishVO();

            //查询动态的发布人信息，封装到vo对象
            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            vo.setTags(userInfo.getTags().split(","));

            //把Publish封装到vo对象
            BeanUtils.copyProperties(publish, vo);
            vo.setId(publish.getId().toHexString());
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setDistance("50米");
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));

            //如果当前用户已经点赞了此动态，这个值应该是1；否则是0
            Boolean hasLike = redisTemplate.hasKey("publish_like_" + userId + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLike ? 1 : 0);
            vo.setHasLoved(0);

            voList.add(vo);
        }

        //4. 构造返回值
        PageResult<PublishVO> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult, voPageResult);
        voPageResult.setItems(voList);
        log.info("查询用户{}的好友动态列表：{}", userId, voPageResult);
        return ResponseEntity.ok(voPageResult);
    }

    /**
     * 查询用户自己的动态（相册）
     */
    public ResponseEntity findAlbumPublishList(int page, int pagesize, Long userId) {
        if (userId == null) {
            userId = UserHolder.getUserId();
        }

        //1. 查询用户的相册动态列表
        PageResult<Publish> pageResult = publishApi.findAlbumPublishList(userId, page, pagesize);

        //2. 转换成VO
        List<Publish> publishList = pageResult.getItems();
        List<PublishVO> voList = new ArrayList<>();
        for (Publish publish : publishList) {
            PublishVO vo = new PublishVO();

            //查询动态的发布人信息，封装到vo对象
            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            vo.setTags(userInfo.getTags().split(","));

            //把Publish封装到vo对象
            BeanUtils.copyProperties(publish, vo);
            vo.setId(publish.getId().toHexString());
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setDistance("50米");
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));

            //如果当前用户已经点赞了此动态，这个值应该是1；否则是0
            Boolean hasLike = redisTemplate.hasKey("publish_like_" + userId + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLike ? 1 : 0);
            vo.setHasLoved(0);
            voList.add(vo);
        }

        //3. 构造返回值
        PageResult<PublishVO> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult, voPageResult);
        voPageResult.setItems(voList);

        return ResponseEntity.ok(voPageResult);
    }

    /**
     * 对动态点赞
     * <p>
     * 要明确的：谁 对 什么内容  做了  什么操作
     *
     * @param publishId 动态id
     */
    public ResponseEntity like(String publishId) {
        //1. 获取当前用户
        Long userId = UserHolder.getUserId();

        //2. 封装数据Comment对象
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(1);
        comment.setPubType(1);
        comment.setUserId(userId);

        Publish publish = publishApi.findById(publishId);
        comment.setPublishUserId(publish.getUserId());


        //3. 保存评论数据
        long count = commentApi.save(comment);

        //4. 把点赞记录存储到Redis里
        redisTemplate.opsForValue().set("publish_like_" + userId + "_" + publishId, "1");

        //5. 给大数据推荐系统发送消息
        mqService.likePublishMessage(publishId);

        return ResponseEntity.ok(count);
    }

    /**
     * 对动态取消点赞
     *
     * @param publishId 动态id
     */
    public ResponseEntity dislike(String publishId) {
        //1. 调用API，把之前保存的Comment删除掉，得到最新计数
        //1.2 准备删除的条件：{userId: 124, publishId: xxxx, commentType: 1}
        Comment comment = new Comment();
        comment.setUserId(UserHolder.getUserId());
        comment.setPublishId(new ObjectId(publishId));
        comment.setCommentType(1);
        //1.2 调用API，删除Comment数据
        long count = commentApi.remove(comment);

        //2. 从Redis里删除之前的点赞记录
        redisTemplate.delete("publish_like_" + UserHolder.getUserId() + "_" + publishId);

        // 给大数据推荐系统发送消息
        mqService.unlikePublishMessage(publishId);

        //3. 返回结果：最新的计数
        return ResponseEntity.ok(count);
    }

    public ResponseEntity findPublishById(String publishId) {
        //1. 调用API ，查询单条动态
        Publish publish = publishApi.findById(publishId);

        //2. 转换成VO
        PublishVO vo = new PublishVO();
        //查询动态的发布人信息，封装到vo对象
        UserInfo userInfo = userInfoApi.findById(publish.getUserId());
        BeanUtils.copyProperties(userInfo, vo);
        vo.setTags(userInfo.getTags().split(","));

        //把Publish封装到vo对象
        BeanUtils.copyProperties(publish, vo);
        vo.setId(publish.getId().toHexString());
        vo.setImageContent(publish.getMedias().toArray(new String[]{}));
        vo.setDistance("50米");
        vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));

        //如果当前用户已经点赞了此动态，这个值应该是1；否则是0
        Boolean hasLike = redisTemplate.hasKey("publish_like_" + UserHolder.getUserId() + "_" + publish.getId().toHexString());
        vo.setHasLiked(hasLike ? 1 : 0);
        vo.setHasLoved(0);

        // 给大数据推荐系统发送消息
        mqService.watchPublishMessage(publishId);

        return ResponseEntity.ok(vo);
    }

    /**
     * 查询当前用户的访客记录
     */
    public ResponseEntity findVisitorList() {
        //从Redis里取出上次查看访客记录的时间
        String lastTime = redisTemplate.opsForValue().get("visitor_time_" + UserHolder.getUserId());

        List<Visitor> visitorList = null;
        if (lastTime == null) {
            //如果Redis里没有上次查看时间，这次就查看前5条访客记录
            visitorList = visitorApi.findVisitorListByCount(UserHolder.getUserId(), 5);
        } else {
            //如果Redis里有上次查看时间，这次就查看上次时间之后新的访客记录
            visitorList = visitorApi.findVisitorListByStartTime(UserHolder.getUserId(), Long.valueOf(lastTime));
        }

        //本次查询，把时间记录到Redis
        redisTemplate.opsForValue().set("visitor_time_" + UserHolder.getUserId(), String.valueOf(System.currentTimeMillis()));

        //转换成VO
        List<VisitorVO> voList = new ArrayList<>();
        for (Visitor visitor : visitorList) {
            VisitorVO vo = new VisitorVO();

            UserInfo userInfo = userInfoApi.findById(visitor.getVisitorUserId());
            BeanUtils.copyProperties(userInfo, vo);

            voList.add(vo);
        }

        return ResponseEntity.ok(voList);
    }
}